﻿using System;

public class Building
{
    private ArrayList<Person> people;
    private ArrayList<Floor> floors; //Holds a counter of the people on the floor
    private ArrayList<Elevator> elevators;

    private Date timer;
    private boolean flag;

    public Building()
    {
        people = new ArrayList<Person>();
        floors = new ArrayList<Floor>();
        elevators = new ArrayList<Elevator>();
        timer = new Date();
        flag = true;
        //elevators.add(new Elevator(0, 10));  // don't necessarily have to use byte... but would save memory...
    }

    public Building(ArrayList<Elevator> e, ArrayList<Floor> f, ArrayList<Person> p)
    {
        this.elevators = e;
        this.floors = f;
        this.people = p;
    }

    /*
     * Called by a person, to request the elevator to come to the floor
     */
    void requestElevator(boolean goUp, int floorID)
    {
        int deltaFloors = Integer.MAX_VALUE;
        int nearestElevator = -1;
        for (int i = 0; i < elevators.size(); i++)
        {
            if (goUp)
            {
                if (elevators.get(i).goesToFloor(floorID) && elevators.get(i).goingUp())
                {
                    if (java.lang.Math.abs(elevators.get(i).getCurrentFloor() - floorID) < deltaFloors)
                    {
                        deltaFloors = java.lang.Math.abs(elevators.get(i).getCurrentFloor() - floorID);
                        nearestElevator = i;
                    }
                }
            }
            else
            {
                if (elevators.get(i).goesToFloor(floorID) && !elevators.get(i).goingUp())
                {
                    if (java.lang.Math.abs(elevators.get(i).getCurrentFloor() - floorID) < deltaFloors)
                    {
                        deltaFloors = java.lang.Math.abs(elevators.get(i).getCurrentFloor() - floorID);
                        nearestElevator = i;
                    }
                }
            }
        }
        if (nearestElevator != -1)
        {
            elevators.get(nearestElevator).addToQueue(floorID);
        }
    }

    /*
     * Moves people from the elevator onto the floor
     */
    /*void moveToFloor(){
        for (int i = 0; i < people.size(); i++){
            if (people.get(i).inElevator()){
                if (!people.get(i).getElevator().isMoving() && !people.get(i).getElevator().isDoorClosed()){
                    if (people.get(i).getFutureFloor() == people.get(i).getElevator().getCurrentFloor()){
                        people.get(i).getElevator().removePerson(); // Remove a person from the elevator counter
                        people.get(i).changeFloor(people.get(i).getElevator().getCurrentFloor()); // Give them the floor
                        this.addPersonToFloor(people.get(i).getElevator().getCurrentFloor()); // Add person to floor counter
                        people.get(i).setInElevator(false); // Remove the elevator
                    }
                }
            }
        }
    }*/

    /*
     * Moves people from the floor to the elevator
     */
    void movePeople()
    {
        for (int i = 0; i < people.size(); i++)
        {
            if (people.get(i).inElevator())
            {
                if (!people.get(i).getElevator().isMoving() && !people.get(i).getElevator().isDoorClosed())
                {
                    if (people.get(i).getFutureFloor() == people.get(i).getElevator().getCurrentFloor())
                    {
                        people.get(i).getElevator().removePerson(); // Remove a person from the elevator counter
                        people.get(i).changeFloor(people.get(i).getElevator().getCurrentFloor()); // Give them the floor
                        this.addPersonToFloor(people.get(i).getElevator().getCurrentFloor()); // Add person to floor counter
                        people.get(i).setInElevator(false); // Remove the elevator
                    }
                }
            }
        }

        for (int i = 0; i < elevators.size(); i++)
        {
            if (!elevators.get(i).isMoving() && !elevators.get(i).isDoorClosed())
            {
                for (int j = 0; j < people.size(); j++)
                {
                    if (elevators.get(i).getCurrentFloor() == people.get(j).getCurrentFloor() && !people.get(j).inElevator())
                    {

                        if (people.get(j).getCurrentFloor() < people.get(j).getFutureFloor() && elevators.get(i).goingUp()
                                && elevators.get(i).goesToFloor(people.get(j).getFutureFloor()))
                        {
                            this.removePersonFromFloor(people.get(j).getCurrentFloor()); // Remove person from the floor counter
                            people.get(j).setElevator(elevators.get(i));
                            people.get(j).setInElevator(true);
                            elevators.get(i).addPerson(); // Add a person to the elevator counter
                            this.requestElevator(true, people.get(j).getFutureFloor());
                        }
                        else if (people.get(j).getCurrentFloor() > people.get(j).getFutureFloor() && !elevators.get(i).goingUp()
                              && elevators.get(i).goesToFloor(people.get(j).getFutureFloor()))
                        {
                            this.removePersonFromFloor(people.get(j).getCurrentFloor()); // Remove person from the floor counter
                            people.get(j).setElevator(elevators.get(i));
                            people.get(j).setInElevator(true);
                            elevators.get(i).addPerson(); // Add a person to the elevator counter
                            this.requestElevator(false, people.get(j).getFutureFloor());
                        }

                    }
                }

            }
            elevators.get(i).setDoorClosed(true);
        }
    }

    void removePersonFromFloor(int floorID)
    {
        this.floors.get(floorID).decrementPeople();
        //this.floors.set(floorID, (floors.get(floorID)-1));
    }

    void addPersonToFloor(int floorID)
    {
        this.floors.get(floorID).incrementPeople();
        //this.floors.set(floorID, (floors.get(floorID)+1));
    }

    int getPeopleOnFloor(int floorID)
    {
        return this.floors.get(floorID).getNumberOfPeople();
    }

    void createElevator(int minFloor, int maxFloor, ArrayList<Boolean> floorList)
    {
        elevators.add(new Elevator(minFloor, maxFloor, floorList));
        for (int i = 0; i < (maxFloor - minFloor + 1); i++)
        {
            floors.add(new Floor("Floor " + i));
        }
        //this.createFloors(maxFloor-minFloor+1);
    }

    void removeElevator(Elevator e)
    {
        elevators.remove(e);
    }

    void createFloors(ArrayList<String> floorNames)
    {
        for (int i = 0; i < floorNames.size(); i++)
        {
            floors.add(new Floor(floorNames.get(i)));
        }
    }

    void createPerson(int startFloor, int endFloor)
    {
        people.add(new Person(this, startFloor, endFloor));
    }

    Date getTime()
    {
        return timer;
    }

    ArrayList<Elevator> getElevators()
    {
        return elevators;
    }

    ArrayList<Person> getPeople()
    {
        return people;
    }

    public void run()
    {
        for (; ; )
        {
            for (int i = 0; i < this.people.size(); i++)
            {
                this.getPeople().get(i).callElevator();
            }
            for (int i = 0; i < this.elevators.size(); i++)
            {
                if (!this.getElevators().get(i).isDoorClosed() && !this.elevators.get(i).isMoving())
                {
                    this.movePeople();
                }
                else if (this.elevators.get(i).isDoorClosed() && !this.elevators.get(i).isMoving())
                {
                    this.elevators.get(i).elevatorAction();
                }
                else if (this.elevators.get(i).isDoorClosed() && this.elevators.get(i).isMoving())
                {
                    this.elevators.get(i).moveElevator();
                }
            }
        }
    }

    int getNumberOfFLoors()
    {
        return floors.size();
    }
}
